package com.terry.trace.plugin;

import com.alibaba.ttl.threadpool.TtlExecutors;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

/**
 * SpringBoot 异步线程池 公共类
 * 使用方式：方法上加@Async注解即可使用
 * 注意：公共的异步线程池。适用于任务不是很频繁执行，且任务执行时间短的任务。
 * 如果用于频繁执行，且执行时间长的任务，会导致线程池处理不过来，导致任务阻塞在队列；或者队列满了，线程到达最大值，无法处理的任务只能被丢弃
 * @author jiangyaopeng
 */
@Configuration
public class SpringAsyncConfig {

    /** 线程池配置核心线程数量 */
    @Value("${asyncCommonThreadPool.corePoolSize:10}")
    private int corePoolSize;

    /** 线程池配置最大线程数量 */
    @Value("${asyncCommonThreadPool.maxPoolSize:20}")
    private int maxPoolSize;

    /** 线程池配置线程队列长度*/
    @Value("${asyncCommonThreadPool.queueCapacity:1000}")
    private int queueCapacity;

    /**
     * 通过重写getAsyncExecutor方法，制定默认的任务执行由该方法产生
     * <p>
     * 配置类实现AsyncConfigurer接口并重写getAsyncExecutor方法，并返回一个ThreadPoolTaskExecutor
     * 这样我们就获得了一个基于线程池的TaskExecutor
     */
    @Bean
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setThreadNamePrefix("CommonThreadPoolTaskExecutor-");
        taskExecutor.setCorePoolSize(this.corePoolSize);
        taskExecutor.setMaxPoolSize(this.maxPoolSize);
        taskExecutor.setQueueCapacity(this.queueCapacity);
        taskExecutor.initialize();
        // 使用阿里TTL工具修饰线程池，使得TransmittableThreadLocal中数据可以从上层线程透传到线程池中的线程(非TransmittableThreadLocal的ThreadLocal数据不会透传)
        return TtlExecutors.getTtlExecutor(taskExecutor);
    }
}